﻿Imports SlimDX
Imports SlimDX.Direct3D9

Public Class ShaderWater
    Implements IShader
    Structure RippleBlock
        Dim Factor As Single
        Dim Repeat As Single
        Dim Angle As Single
        Dim Velocity As Single
        Dim Offset As Vector4
        Dim RippleMap As Texture
    End Structure
    Dim BaseMap As Texture
    Dim EnvironmentMap As CubeTexture
    Dim Ripples(3) As RippleBlock

    Dim AlphaModulates As Boolean
    Dim ColorModulates As Boolean

    Dim PerpendicularBrightness As Single
    Dim ParallelBrightness As Single
    Dim PerpendicularColor As Color4
    Dim ParallelColor As Color4

    Dim RippleCount As Integer
    Dim RippleScale As Single
    Dim RippleAngle As Single
    Dim RippleVelocity As Single

    Dim Flags As Short

    Sub New(ByVal sglaTag As Magic.Core.Tag)
        AddHandler sglaTag.TagHasChanged, AddressOf Changed
        Dim BaseIndex As Integer = sglaTag("base map")
        Dim CubeIndex As Integer = sglaTag("reflection map:[0,1]")
        Dim RippleIndex As Integer = sglaTag("ripple maps")

        Flags = sglaTag(12)

        AlphaModulates = Flags And 1 <> 0
        ColorModulates = Flags And 2 <> 0

        PerpendicularBrightness = sglaTag("view perpendicular brightness:[0,1]")
        ParallelBrightness = sglaTag("view parallel brightness:[0,1]")

        PerpendicularColor = New SlimDX.Color4(1, sglaTag("view perpendicular tint color")(0), sglaTag("view perpendicular tint color")(1), sglaTag("view perpendicular tint color")(2))
        ParallelColor = New SlimDX.Color4(1, sglaTag("view parallel tint color")(0), sglaTag("view parallel tint color")(1), sglaTag("view parallel tint color")(2))

        If BaseIndex > -1 Then
            BaseMap = New Bitmap(magicMap.Library(BaseIndex)).Texture
        Else
            BaseMap = Globals.default2d(IShader.DefaultTextures.Additive)
        End If
        If CubeIndex > -1 Then
            EnvironmentMap = New Bitmap(magicMap.Library(CubeIndex)).Cube
        Else
            EnvironmentMap = Globals.defaultCube(IShader.DefaultTextures.SignedAdditive)
        End If

        RippleCount = CType(sglaTag("ripples"), Array).GetLength(0)
        RippleAngle = sglaTag("ripple animation angle:[0,360]")
        RippleVelocity = sglaTag("ripple animation velocity")
        RippleScale = sglaTag("ripple scale")

        For x As Integer = 0 To 3
            If x >= RippleCount Then
                Ripples(x) = Nothing
            Else
                Ripples(x) = New RippleBlock

                Ripples(x).Angle = CType(sglaTag("ripples"), Array).GetValue(x, 4)
                Ripples(x).Factor = CType(sglaTag("ripples"), Array).GetValue(x, 2)
                Ripples(x).Offset = New Vector4(CType(sglaTag("ripples"), Array).GetValue(x, 6)(0), CType(sglaTag("ripples"), Array).GetValue(x, 6)(1), 0.0F, 0.0F)
                Ripples(x).Repeat = CType(sglaTag("ripples"), Array).GetValue(x, 7)
                Ripples(x).Velocity = CType(sglaTag("ripples"), Array).GetValue(x, 5)

                If RippleIndex > -1 Then
                    Ripples(x).RippleMap = New Bitmap(magicMap.Library(RippleIndex)).Texture(CType(sglaTag("ripples"), Array).GetValue(x, 8))
                Else
                    Ripples(x).RippleMap = Globals.default2d(IShader.DefaultTextures.Vector)
                End If
            End If
        Next
    End Sub
    Sub Changed(ByVal sglaTag As Magic.Core.Tag)
        Dim BaseIndex As Integer = sglaTag("base map")
        Dim CubeIndex As Integer = sglaTag("reflection map:[0,1]")
        Dim RippleIndex As Integer = sglaTag("ripple maps")

        Flags = sglaTag(12)

        AlphaModulates = Flags And 1 <> 0
        ColorModulates = Flags And 2 <> 0

        PerpendicularBrightness = sglaTag("view perpendicular brightness:[0,1]")
        ParallelBrightness = sglaTag("view parallel brightness:[0,1]")

        PerpendicularColor = New SlimDX.Color4(1, sglaTag("view perpendicular tint color")(0), sglaTag("view perpendicular tint color")(1), sglaTag("view perpendicular tint color")(2))
        ParallelColor = New SlimDX.Color4(1, sglaTag("view parallel tint color")(0), sglaTag("view parallel tint color")(1), sglaTag("view parallel tint color")(2))

        If BaseIndex > -1 Then
            BaseMap = New Bitmap(magicMap.Library(BaseIndex)).Texture
        Else
            BaseMap = Globals.default2d(IShader.DefaultTextures.Additive)
        End If
        If CubeIndex > -1 Then
            EnvironmentMap = New Bitmap(magicMap.Library(CubeIndex)).Cube
        Else
            EnvironmentMap = Globals.defaultCube(IShader.DefaultTextures.SignedAdditive)
        End If

        RippleCount = CType(sglaTag("ripples"), Array).GetLength(0)
        RippleAngle = sglaTag("ripple animation angle:[0,360]")
        RippleVelocity = sglaTag("ripple animation velocity")
        RippleScale = sglaTag("ripple scale")

        For x As Integer = 0 To 3
            If x >= RippleCount Then
                Ripples(x) = Nothing
            Else
                Ripples(x) = New RippleBlock

                Ripples(x).Angle = CType(sglaTag("ripples"), Array).GetValue(x, 4)
                Ripples(x).Factor = CType(sglaTag("ripples"), Array).GetValue(x, 2)
                Ripples(x).Offset = New Vector4(CType(sglaTag("ripples"), Array).GetValue(x, 6)(0), CType(sglaTag("ripples"), Array).GetValue(x, 6)(1), 0.0F, 0.0F)
                Ripples(x).Repeat = CType(sglaTag("ripples"), Array).GetValue(x, 7)
                Ripples(x).Velocity = CType(sglaTag("ripples"), Array).GetValue(x, 5)

                If RippleIndex > -1 Then
                    Ripples(x).RippleMap = New Bitmap(magicMap.Library(RippleIndex)).Texture(CType(sglaTag("ripples"), Array).GetValue(x, 8))
                Else
                    Ripples(x).RippleMap = Globals.default2d(IShader.DefaultTextures.Vector)
                End If
            End If
        Next
    End Sub
    Public Overloads Sub BeginPass(ByVal pass As Integer) Implements IShader.BeginPass
        If (pass = 0) Then
            xDevice.SetRenderState(RenderState.AlphaBlendEnable, True)
            xDevice.SetRenderState(RenderState.AlphaTestEnable, False)

            xDevice.SetRenderState(RenderState.SourceBlend, Blend.SourceColor)
            xDevice.SetRenderState(RenderState.DestinationBlend, Blend.One)
            xDevice.SetRenderState(RenderState.BlendOperation, BlendOperation.Add)

            xDevice.SetRenderState(RenderState.CullMode, Cull.None)
        End If
        swatEffect.BeginPass(pass)
    End Sub
    Public Overloads Sub EndPass() Implements IShader.EndPass
        swatEffect.EndPass()
    End Sub

    Public Overloads Function BeginShader(ByVal tLightmap As Texture) As Integer Implements IShader.BeginShader
        swatEffect.SetValue("cameraPosition", New Vector4(Camera.Position.X, Camera.Position.Y, Camera.Position.Z, 1.0F))
        swatEffect.SetValue("world", xDevice.GetTransform(TransformState.World))
        swatEffect.SetValue("worldViewProjection", xDevice.GetTransform(TransformState.World) * xDevice.GetTransform(TransformState.View) * xDevice.GetTransform(TransformState.Projection))

        swatEffect.SetTexture("BaseMap", BaseMap)
        swatEffect.SetTexture("EnvironmentMap", EnvironmentMap)

        swatEffect.SetValue("alphaModulatesReflection", AlphaModulates)
        swatEffect.SetValue("colorModulatesBackground", ColorModulates)

        swatEffect.SetValue("rippleCount", RippleCount)
        swatEffect.SetValue("rippleScale", RippleScale)
        swatEffect.SetValue("rippleAngle", RippleAngle)

        swatEffect.SetValue("perpendicularBrightness", PerpendicularBrightness)
        swatEffect.SetValue("parallelBrightness", ParallelBrightness)
        swatEffect.SetValue("perpendicularColor", PerpendicularColor)
        swatEffect.SetValue("parallelColor", ParallelColor)

        For x As Integer = 0 To 3
            If x >= RippleCount Then
                swatEffect.SetTexture("RippleMap" & x.ToString, Globals.default2d(IShader.DefaultTextures.Vector))
            Else
                swatEffect.SetValue("angle" & x.ToString, Ripples(x).Angle)
                swatEffect.SetValue("factor" & x.ToString, Ripples(x).Factor)
                swatEffect.SetValue("repeat" & x.ToString, Ripples(x).Repeat)
                swatEffect.SetValue("offset" & x.ToString, Ripples(x).Offset)
                swatEffect.SetTexture("RippleMap" & x.ToString, Ripples(x).RippleMap)

                Dim frequency As Single = RippleVelocity * Ripples(x).Velocity
                If frequency = 0 Then frequency = Ripples(x).Velocity
                swatEffect.SetValue("animation" & x.ToString, Animate(6, 1.0F / frequency, 1.0F))
            End If
        Next

        If (tLightmap Is Nothing) Then
            swatEffect.SetTexture("LightMap", Globals.default2d(IShader.DefaultTextures.Multiplicative))
        Else
            swatEffect.SetTexture("LightMap", tLightmap)
        End If

        swatEffect.Technique = "Water"
        Return swatEffect.Begin(FX.DoNotSaveState)
    End Function
    Public Overloads Sub EndShader() Implements IShader.EndShader
        swatEffect.End()
    End Sub
End Class
